package dpreview;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdom.input.*;
import org.jdom.xpath.*;
import org.jdom.*;
import java.util.*;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

public class CameraSummaryXML {

    Hashtable<String,BrandSummary> brandS;

    public static void main(String[] args) {
	new CameraSummaryXML().init();
    }

    void init(){
	// adapta a jvn as definicoes locais dos EUA
        Locale.setDefault(Locale.ENGLISH);

	//hashtable com Marca -> Sumario da Marca
	brandS = new Hashtable<String, BrandSummary>();

	// abre interface para escolha de ficheiros
	FileChooserApp fca = new FileChooserApp();
	File[] files = fca.openFiles();

	if (files==null) {
	    System.out.println("You must select one or more files! Exiting...");
	    System.exit(0);
	}

	doSummary(files);

	writeSummaryXML();
    }

    void doSummary(File[] files){
    	// ANALISA CADA UM DOS FICHEIROS PASSADOS POR PARAMETRO
	for(int j =0; j < files.length; j++) {

	    SAXBuilder builder = new SAXBuilder();
	    Document myXML;
	    try {
		// Parse our XML file into a Document object (uses SAX)
		myXML = builder.build(files[j].getAbsolutePath());

		// chamada do metodo para validacao do XML a partir do schema criado
		/* if(!validateXML(myXML)) {
		    System.out.println("File "+files[j].getAbsolutePath()+" invalid! Skipped");
		    break;
		}*/

		// EXTRAI A MARCA
		XPath manufacturer = XPath.newInstance("//search/@brand");
		String manuf = (String) manufacturer.valueOf(myXML);
		System.out.println("> "+manuf);
		BrandSummary bs = new BrandSummary(); //vai guardando os dados que se pretendem exportar para XML

		// RECORRE A FUNCAO COUNT DO XPATH PARA OBTER O NUMERO DE CAMERAS DA MARCA
		XPath cameras = XPath.newInstance("count(//search/camera)");
		double d = (Double) cameras.selectSingleNode(myXML);
		System.out.println(d+" cameras para a marca "+manuf);
		bs.setN_cameras((int)d);

		// EXTRAI TODAS AS DATAS ANNOUNCED
		XPath announced = XPath.newInstance("//search/camera/announced"); //datas announced
		List dates_announced = announced.selectNodes(myXML);

		Vector<Date> dates = new Vector<Date>();
		Vector<String> models = new Vector<String>();

		Iterator it = dates_announced.iterator();

		// guarda as datas e respectivo modelo num vector para futura comparacao
		while (it.hasNext()) {
		    Element date = (Element) it.next();

		    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		    Date d_aux=null;
		    try {
			d_aux = df.parse(date.getValue());
		    } catch (ParseException ex) {
			Logger.getLogger(CameraSummaryXML.class.getName()).log(Level.SEVERE, null, ex);
		    }
		    if (d_aux!=null) {

			dates.add(d_aux);
			models.add(date.getParentElement().getAttributeValue("model"));
		    }

		}

		//calculo das datas mais recente e antiga e respectivo modelo
		Date recent = null;
		Vector<String> model_recent= new Vector<String>();

		Date oldest = null;
		Vector<String> model_oldest = new Vector<String>();

		Date d_aux=null;

		for (int i =0; i < dates.size(); i ++) {
		    d_aux = dates.elementAt(i);

			if(d_aux!=null) {
			    if ( recent == null) {
				recent = d_aux;
			    } if (oldest == null) {
				oldest = d_aux;
			    }

			    if ( (d_aux.getTime()-recent.getTime()) > 0 ) {
				recent = d_aux;
				model_recent.removeAllElements();
				model_recent.add(models.elementAt(i));
			    } else if ((d_aux.getTime()-oldest.getTime()) < 0 ) {
				oldest = d_aux;
				model_oldest.removeAllElements();
				model_oldest.add(models.elementAt(i));
			    } else  if ( (d_aux.getTime()-recent.getTime()) == 0 ) {
				model_recent.add(models.elementAt(i));
			    } else if ((d_aux.getTime()-oldest.getTime()) == 0 ) {
				model_oldest.add(models.elementAt(i));
			    }

			}
		}

		System.out.println("Data mais recente: "+recent+" n modelos: "+model_recent.size());
		bs.setMost_recent(recent);
		bs.setModel_most_recent(model_recent);

		System.out.println("Data mais antiga: "+oldest+" n modelos: "+model_oldest.size());
		bs.setOldest(oldest);
		bs.setModel_oldest(model_oldest);

		// calculo da resolucao maxima
		 XPath max_resolution = XPath.newInstance("//search/camera/max_resolution");
		List list_max_resolution = max_resolution.selectNodes(myXML);

		it = list_max_resolution.iterator();
		int res_aux_w=0;
		int res_aux_h=0;
		//String model_res="";
		Vector<String> model_max_res = new Vector<String>();
		while (it.hasNext()) {
		// Get the details of the current CD and print them out
		    Element resolution = (Element) it.next();
		    //System.out.println("Resolution: "+resolution.getChildText("width"));
		    int res_w = Integer.parseInt(resolution.getChildText("width"));
		    int res_h = Integer.parseInt(resolution.getChildText("height"));

		    if ( (res_w*res_h) > (res_aux_w*res_aux_h)) {
			res_aux_w = res_w;
			res_aux_h = res_h;
			//model_res = resolution.getParentElement().getAttributeValue("model");
			model_max_res.removeAllElements();
			model_max_res.add(resolution.getParentElement().getAttributeValue("model"));
		    } else if ((res_w*res_h) == (res_aux_w*res_aux_h)) {
			model_max_res.add(resolution.getParentElement().getAttributeValue("model"));
		    }
		}

		System.out.println("Resolucao maxima de: "+res_aux_w+" n modelos: "+model_max_res.size());
		bs.setMax_resolution_w(res_aux_w);
		bs.setMax_resolution_h(res_aux_h);
		bs.setModel_max_resolution(model_max_res);

		// calculo das resolucoes minimas
		 XPath min_resolution = XPath.newInstance("//search/camera/lower_resolutions");
		List list_min_resolution = min_resolution.selectNodes(myXML);

		it = list_min_resolution.iterator();
		Vector<String> model_min_res = new Vector<String>();
		while (it.hasNext()) {
		    Element resolution = (Element) it.next();
		    if (resolution!=null) {
			List min_resolutions = resolution.getChildren();
			Iterator it2 = min_resolutions.iterator();
			while(it2.hasNext()) {
			    Element lower_res = (Element) it2.next();
			    if (lower_res!=null) {
				int res_w = Integer.parseInt(lower_res.getChildText("width"));
				int res_h = Integer.parseInt(lower_res.getChildText("height"));

				if ( (res_w*res_h )< (res_aux_w*res_aux_h)) {
				    res_aux_w = res_w;
				    res_aux_h = res_h;
				    //model_res = lower_res.getParentElement().getParentElement().getAttributeValue("model");
				    model_min_res.removeAllElements();
				    model_min_res.add(lower_res.getParentElement().getParentElement().getAttributeValue("model"));
				} else if ( (res_w*res_h ) == (res_aux_w*res_aux_h)) {
				    model_min_res.add(lower_res.getParentElement().getParentElement().getAttributeValue("model"));
				}
			    }
			}
		    }
		}

		System.out.println("Resolucao minima de: "+res_aux_w+" n modelos: "+model_min_res.size());
		bs.setMin_resolution_w(res_aux_w);
		bs.setMin_resolution_h(res_aux_h);
		bs.setModel_min_resolution(model_min_res);

		// vai buscar todos os modelos para uma certa brand
		XPath cameras2 = XPath.newInstance("//search/camera");
		List list_cameras = cameras2.selectNodes(myXML);

		Iterator it2 = list_cameras.iterator();
		while (it2.hasNext()) {
		    Element m = (Element) it2.next();
		    bs.getModels().add(m.getAttributeValue("model"));
		}

		// se ainda n contem um sumario para esta marca
		if (!brandS.containsKey(manuf))
		    brandS.put(manuf, bs); // guarda o sumario para posterior exportacao
		else //se nao, actualiza o sumario antigo com os possiveis novos dados
		    brandS = updateBrandSummary(brandS, manuf, bs);

	    } catch (JDOMException ex) {
		Logger.getLogger(CameraSummaryXML.class.getName()).log(Level.SEVERE, null, ex);
	    } catch (IOException ex) {
		Logger.getLogger(CameraSummaryXML.class.getName()).log(Level.SEVERE, null, ex);
	    }
	}
    }

    void writeSummaryXML(){
	//escreve o sumario para XML
	Element pubElement = new Element("summary");
	Document myDocument = new Document(pubElement);

	Enumeration e = brandS.keys();
	while (e.hasMoreElements()) {
	    String key = (String) e.nextElement();
	    BrandSummary value =(BrandSummary) brandS.get(key);

	    Element manufacturer = new Element("manufacturer");
	    manufacturer.setAttribute("brand", key );

	    Element n_cameras = new Element("number_cameras");
	    n_cameras.addContent(""+value.getN_cameras());
	    manufacturer.addContent(n_cameras);

	    Element newer = new Element("newest");

	    Element date = new Element("date");
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	    String date_newer = sdf.format(value.getMost_recent());
	    date.addContent(date_newer);

	    newer.addContent(date);

	    Element cameras4 = new Element("cameras");
	    for (int z=0; z<value.getModel_most_recent().size(); z++) {
		Element model = new Element("model");
		model.addContent(value.getModel_most_recent().elementAt(z));
		cameras4.addContent(model);
	    }
	    newer.addContent(cameras4);

	    manufacturer.addContent(newer);

	    Element oldest = new Element("oldest");

	    Element date_older = new Element("date");
	    String date_oldest = sdf.format(value.getOldest());

	    date_older.addContent(date_oldest);
	    oldest.addContent(date_older);

	    Element cameras3 = new Element ("cameras");
	     for (int z=0; z<value.getModel_oldest().size(); z++) {
		Element model = new Element("model");
		model.addContent(value.getModel_oldest().elementAt(z));
		cameras3.addContent(model);
	    }
	    oldest.addContent(cameras3);

	    manufacturer.addContent(oldest);

	    Element max_resolution = new Element("maximum_resolution");

	    //Element resolution = new Element("resolution");

	    Element width = new Element("width");
	    width.addContent(""+value.getMax_resolution_w());
	    max_resolution.addContent(width);

	    Element height = new Element("height");
	    height.addContent(""+value.getMax_resolution_h());
	    max_resolution.addContent(height);

	    //max_resolution.addContent(resolution);
	    Element cameras2 = new Element("cameras");
	   for (int z=0; z<value.getModel_max_resolution().size(); z++) {
		Element model = new Element("model");
		model.addContent(value.getModel_max_resolution().elementAt(z));
		cameras2.addContent(model);
	    }
    	    max_resolution.addContent(cameras2);


	    manufacturer.addContent(max_resolution);

	    Element min_resolution = new Element("minimum_resolution");

	   // Element resolution2 = new Element("resolution");

	    Element width2 = new Element("width");
	    width2.addContent(""+value.getMin_resolution_w());
	    min_resolution.addContent(width2);

	    Element height2 = new Element("height");
	    height2.addContent(""+value.getMin_resolution_h());
	    min_resolution.addContent(height2);

	   // min_resolution.addContent(resolution2);
	   Element cameras = new Element("cameras");
	    for (int z=0; z<value.getModel_min_resolution().size(); z++) {
		Element model = new Element("model");
		model.addContent(value.getModel_min_resolution().elementAt(z));
		cameras.addContent(model);
	    }
	    min_resolution.addContent(cameras);
	    manufacturer.addContent(min_resolution);

	    Element models = new Element("cameras");
	    for (int k=0; k<value.getModels().size(); k++) {
		Element m = new Element("model");
		m.addContent(value.getModels().elementAt(k));
		models.addContent(m);
	    }
	    manufacturer.addContent(models);
	     pubElement.addContent(manufacturer);

	    // Escreve para disco
	    try {
            XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
            OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream("output\\summary.xml"), "UTF-8");

            outputter.output(myDocument, out);
            out.close();
	    } catch(Exception ex) {
		Logger.getLogger(CameraSummaryXML.class.getName()).log(Level.SEVERE, null, ex);
	    }

	}
    }


    Hashtable<String,BrandSummary> updateBrandSummary(Hashtable<String,BrandSummary> b_s,  String mnf, BrandSummary new_bs ) {
	BrandSummary old = b_s.get(mnf);
	old.setN_cameras(old.getN_cameras() + new_bs.getN_cameras()); //actualiza o numero total de cameras para esta marca

	//DATAS DAS MAIS RECENTE E MAIS ANTIGA
	if (old.getMost_recent().getTime() - new_bs.getMost_recent().getTime() <0) { //se a data do mais recente da repeticao é mais recente que a que ja estava
	    old.setMost_recent(new_bs.getMost_recent());					// actualiza o sumario da marca com a data mais recente
	    old.setModel_most_recent(new_bs.getModel_most_recent());
	}
	if (old.getOldest().getTime() - new_bs.getOldest().getTime() > 0) { // se a data do mais antigo da repeticao é mais antiga que a que ja estava
	    old.setOldest(new_bs.getOldest());
	    old.setModel_oldest(new_bs.getModel_oldest());			    //actualiza o sumario da marca com a data mais antiga
	}

	//RESOLUCOES MAXIMAS E MINIMAS
	if ( (old.getMax_resolution_w()*old.getMax_resolution_h()) < (new_bs.getMax_resolution_w()*new_bs.getMax_resolution_h())) {  // se a resolucao da repeticao é maior que a que ja estava
	    old.setMax_resolution_h(new_bs.getMax_resolution_h());	    //actualiza a resolucao maxima no sumário
	    old.setMax_resolution_w(new_bs.getMax_resolution_w());
	    old.setModel_max_resolution(new_bs.getModel_max_resolution());
	}
	if ( (old.getMin_resolution_w()*old.getMin_resolution_h()) > (new_bs.getMin_resolution_w()*new_bs.getMin_resolution_h())) {	   // se a resolucao da repeticao é menor que a que ja estava
	    old.setMin_resolution_h(new_bs.getMin_resolution_h());	    //actualiza a resolucao minima no sumário
	    old.setMin_resolution_w(new_bs.getMin_resolution_w());
	    old.setModel_min_resolution(new_bs.getModel_min_resolution());
	}
	//acrescenta os modelos da repeticao 'a lista de modelos no sumario
	for (int i =0; i<new_bs.getModels().size(); i++)
	    old.getModels().addElement(new_bs.getModels().elementAt(i));
	b_s.put(mnf, old);
	return b_s;
    }

}